﻿module GameLogicFunctions

open SI
open Tile
open Math
open LabyrinthGameState
open Player
open ListUtility
open Microsoft.Xna.Framework

let mutable timeToMove = System.TimeSpan(0,0,0)
let rand = new System.Random()

let rec remove(node : POSITION, tempList : POSITION list) = 
    let head = tempList.Head
    match node with 
    | x when x = head -> tempList.Tail
    | _ -> tempList.Head :: remove(node, tempList.Tail)

let rec removeLast(tempList : POSITION list) = 
    let tail = tempList.Tail
    match tail with 
    | x when x = [] -> []
    | _ -> tempList.Head :: removeLast(tempList.Tail)

let UpdateTilePosition (tile : Tile, row, column) = 
    tile.Update(row, column, tile.mOrientation)
    let index = int(row * 7.f + column)
    gameState.mChessboard.board.[index] <- tile

let RotateRemainedTile() = 
    let tile = gameState.mRemainedTile
    if tile.mOrientation = ORIENTATION.N then
        tile.mOrientation <- ORIENTATION.W
    else if tile.mOrientation = ORIENTATION.S then
        tile.mOrientation <- ORIENTATION.E
    else if tile.mOrientation = ORIENTATION.E then
        tile.mOrientation <- ORIENTATION.N
    else 
        tile.mOrientation <- ORIENTATION.S

let SlideRow(row : float32<tile>, column) = 
    let remainedTile = gameState.mRemainedTile
    if column = 6.f<tile> then
        let temp = gameState.mChessboard.board.[int(row * 7.f)]
        temp.Update(-1.f<tile>, -1.f<tile>, temp.mOrientation)
        for i in 0..5 do
            let index = int(row * 7.f + float32(i + 1) * 1.f<tile>)
            UpdateTilePosition(gameState.mChessboard.board.[index], row, float32(i) * 1.f<tile>)
        UpdateTilePosition(remainedTile, row, 6.f<tile>)
        gameState.mRemainedTile <- temp
    else if column = 0.f<tile> then
        let temp = gameState.mChessboard.board.[int(row * 7.f + 6.f<tile>)]
        temp.Update(-1.f<tile>, -1.f<tile>, temp.mOrientation)
        for i in 0..5 do
            let index = int(row * 7.f + float32(6 - i - 1) * 1.f<tile>)
            UpdateTilePosition(gameState.mChessboard.board.[index], row, float32(6 - i) * 1.f<tile>)
        UpdateTilePosition(remainedTile, row, 0.f<tile>)
        gameState.mRemainedTile <- temp

let SlideColumn(row : float32<tile>, column : float32<tile>) = 
    let remainedTile = gameState.mRemainedTile
    if row = 6.f<tile> then
        let temp = gameState.mChessboard.board.[int(column)]
        temp.Update(-1.f<tile>, -1.f<tile>, temp.mOrientation)
        for i in 0..5 do
            let index = int( float32(i + 1) * 7.f<tile> + column )
            UpdateTilePosition(gameState.mChessboard.board.[index], float32(i) * 1.f<tile>, column)
        UpdateTilePosition(remainedTile, 6.f<tile>, column)
        gameState.mRemainedTile <- temp
    else if row = 0.f<tile> then
        let temp = gameState.mChessboard.board.[int(6.f<tile> * 7.f + column)]
        temp.Update(-1.f<tile>, -1.f<tile>, temp.mOrientation)
        for i in 0..5 do
            let index = int( float32(6 - i - 1) * 7.f<tile> + column )
            UpdateTilePosition(gameState.mChessboard.board.[index], float32(6 - i) * 1.f<tile>, column)
        UpdateTilePosition(remainedTile, 0.f<tile>, column)
        gameState.mRemainedTile <- temp

let InsertTile(position, sequencePos) =  
    let remainedTile = gameState.mRemainedTile
    if position = POSITION.Up then
        SlideColumn( 0.f<tile>, float32(sequencePos + 1) * 1.f<tile>)
    else if position = POSITION.Down then
        SlideColumn( 6.f<tile>, float32(sequencePos + 1) * 1.f<tile>)
    else if position = POSITION.Left then
        SlideRow( float32(sequencePos + 1) * 1.f<tile>, 0.f<tile>)
    else if position = POSITION.Right then
        SlideRow( float32(sequencePos + 1) * 1.f<tile>, 6.f<tile>)
    for player in gameState.mPlayers do
        if (player.mPosition = gameState.mRemainedTile) then
            player.mPosition <- remainedTile

let GetNextGoal(actualTile, player) = 
    let p = player
    let index = int(rand.Next() % gameState.mTileList.Length)
    let mutable temp = gameState.mTileList.[index]
    if (p.mGoalToCatch > 1) then
        while temp.mID = actualTile.mID do
            let index = int(rand.Next() % gameState.mTileList.Length)
            temp <- gameState.mTileList.[index]
        p.mGoalToCatch <- p.mGoalToCatch - 1
    temp
        
let GetNextPlayer() =
    let mutable next = gameState.mPlayers.[0]
    let mutable tempList = gameState.mPlayers
    while tempList.IsEmpty <> true do
        let player = tempList.Head
        if player = gameState.mSelectedPlayer then
            if tempList.Tail.IsEmpty = false then
                next <- tempList.Tail.Head
                tempList <- []
            else
                next <- gameState.mPlayers.[0]
                tempList <- []
        else
            tempList <- tempList.Tail
    next

let MovePlayer(direction) = 
    gameState.mSelectedPlayer.mPosition <- gameState.mChessboard.MoveToCloseTile(gameState.mSelectedPlayer.mPosition, direction)

let MovePlayerOnChessboard(gameTime : Microsoft.Xna.Framework.GameTime, input, selectedTile) = 
    let mutable res = false
    let mutable moveList = gameState.mSelectedPlayer.mPathFinder.mMoves
    if gameState.mSelectedPlayer.mPosition = selectedTile then
        gameState.mSelectedPlayer.mIsMoving <- false
        res <- true
    if gameState.mSelectedPlayer.mIsMoving then
        if moveList.Length > 0 then
            let tempTime = gameTime.TotalGameTime.Subtract(timeToMove)
            if tempTime.Milliseconds >= 500 then
                let move = moveList.[moveList.Length - 1]
                gameState.mSelectedPlayer.mPathFinder.mMoves <- removeLast(moveList) 
                MovePlayer(move)
                timeToMove <- gameTime.TotalGameTime
    else if res = false then
        gameState.mSelectedTile <- selectedTile
        gameState.mSelectedPlayer.mPathFinder.mMoves <- gameState.mSelectedPlayer.mPathFinder.GetMovesToTile(selectedTile)
        if gameState.mSelectedPlayer.mPathFinder.mMoves.Length <> 0 then
            gameState.mSelectedPlayer.mIsMoving <- true
            timeToMove <- gameTime.TotalGameTime
        else
            res <- true
    res

let UpdatePathFindingToGoal() = 
    let mutable temp = false
    let mutable res = true
    let index = int(gameState.mSelectedPlayer.mPosition.mPosition.X * 7.f + gameState.mSelectedPlayer.mPosition.mPosition.Y)
    let position = gameState.mChessboard.board.[index]
    temp <- gameState.mSelectedPlayer.mPathFinder.PathFinding(position, gameState.mSelectedPlayer.mGoal, gameState.mChessboard)
    if gameState.mChessboard.GetNeighbors(gameState.mSelectedPlayer.mPosition).Length = 0 then
        res <- false
    res

let UpdateMoveToGoal(gameTime, selectedTile) =
    let mutable res = false
    if MovePlayerOnChessboard(gameTime, true, selectedTile) = true then
        res <-true
        if gameState.mSelectedPlayer.mPosition = gameState.mSelectedPlayer.mGoal then
            if gameState.mSelectedPlayer.mGoalToCatch = 1 then
                gameState.mWinner <- true
            else
                let nextGoal = GetNextGoal(gameState.mSelectedPlayer.mPosition, gameState.mSelectedPlayer)
                gameState.mSelectedPlayer.mGoal <- nextGoal
        if gameState.mWinner = false then
            gameState.mSelectedPlayer <- GetNextPlayer()
    res